绘制并非总是在内存中的单层画面里完成的。实际上,浏览器在必要时将会把一帧画面绘制成多层画面,然后将这若干层画面合并成一张图片显示到屏幕上。
在页面中新建一个渲染层最好的方式就是使用 will-change 属性,同时再与 transform 属性一起使用,就会创建一个新的复合图层:
`
.element {
will-change: transform;
}
`
对于那些目前还不支持 will-change 属性、但支持创建复合图层的浏览器,可以使用一个 3D transform 属性来强制浏览器创建一个新的复合图层:
`
.element {
transform: translate3d(0,0,0);
}
`
标签 <video>
,<canvas>
可以创建复合图层
注意: 别盲目创建复合图层,一定要分析其实际性能表现。因为创建复合图层是有代价的,每创建一个新的复合图层,就意味着新的内存分配和更复杂的层的管理。并且在移动端 GPU 和 CPU 的带宽有限制,创建的复合图层过多时,合成也会消耗跟多的时间。
元素提升为复合图层后,transform 和 opacity 才不会触发 paint,如果不是复合图层,则其依然会触发重绘。
# 普通图层与复合图层
- 可以认为默认只有一个复合图层,所有的 DOM 节点都是在这个复合图层下的
- 如果开启了硬件加速功能,可以将某个节点变成复合图层
- 复合图层之间的绘制互不干扰,由 GPU 直接控制
- 而简单图层中,就算是 absolute 等布局,变化时不影响整体的回流,但是由于在同一个图层中,仍然是会影响绘制的,因此做动画时性能仍然很低。而复合层是独立的,所以一般做动画推荐使用硬件加速。
# 硬件加速变成复合图层
硬件加速技术如下
- 最常用的方式:translate3d、translateZ
- opacity 属性/过渡动画(需要动画执行的过程中才会创建合成层,动画没有开始或结束后元素还会回到之前的状态)
- will-change 属性,一般配合 opacity 与 translateZ 使用 经测试,除了上述可以引发硬件加速的属性外,其它属性并不会变成复合层。
absolute 和硬件加速的区别
absolute 虽然可以脱离普通文档流,但是无法脱离默认复合层。所以,就算 absolute 中信息改变时不会改变普通文档流中 render 树,但浏览器最终绘制时,是整个复合层绘制的,absolute 中信息的改变仍然会影响整个复合层的绘制。
硬件加速直接就是在另一个复合层了,所以它的信息改变不会影响默认复合层。
复合层的作用?
一般一个元素开启硬件加速后会变成复合图层,可以独立于普通文档流中,改动后可以避免整个页面重绘,提升性能。
硬件加速时请使用 index
使用硬件加速时,尽可能的使用index,防止浏览器默认给后续的元素创建复合层渲染。如果a是一个复合图层,而且b在a上面,那么b也会被隐式转为一个复合图层,这点需要特别注意。